home *** CD-ROM | disk | FTP | other *** search
- #!/bin/bash
-
- # $Header$
-
- # bash replacement for the original euse by Arun Bhanu
- # Author: Marius Mauch <genone@gentoo.org>
- # Version: 0.2
- # Licensed under the GPL v2
-
- PROGRAM_NAME=euse
- PROGRAM_VERSION=0.1
-
- MAKE_CONF_PATH=/etc/make.conf
- MAKE_GLOBALS_PATH=/etc/make.globals
- MAKE_PROFILE_PATH=/etc/make.profile
- MAKE_CONF_BACKUP_PATH=/etc/make.conf.euse_backup
-
- [ -z "${MODE}" ] && MODE="showhelp" # available operation modes: showhelp, showversion, showdesc, showflags, modify
-
- parse_arguments() {
- if [ -z "${1}" ]; then
- return
- fi
- while [ -n "${1}" ]; do
- case "${1}" in
- -h | --help) MODE="showhelp";;
- -v | --version) MODE="showversion";;
- -i | --info) MODE="showdesc";;
- -l | --local) SCOPE="local";;
- -g | --global) SCOPE="global";;
- -a | --active) MODE="showflags";;
- -E | --enable) MODE="modify"; ACTION="add";;
- -D | --disable) MODE="modify"; ACTION="remove";;
- -P | --prune) MODE="modify"; ACTION="prune";;
- -*)
- echo "ERROR: unknown option ${1} specified."
- echo
- MODE="showhelp"
- ;;
- *)
- ARGUMENTS="${ARGUMENTS} ${1}"
- ;;
- esac
- shift
- done
- }
-
- error() {
- echo "ERROR: ${1}"
- set +f
- exit 1
- }
-
- check_sanity() {
- # file permission tests
- local descdir
-
- descdir="$(get_portdir)/profiles"
-
- [ ! -r "${MAKE_CONF_PATH}" ] && error "${MAKE_CONF_PATH} is not readable"
- [ ! -r "${MAKE_GLOBALS_PATH}" ] && error "${MAKE_GLOBALS_PATH} is not readable"
- [ ! -h "${MAKE_PROFILE_PATH}" ] && error "${MAKE_PROFILE_PATH} is not a symlink"
- [ -z "$(get_portdir)" ] && error "\$PORTDIR couldn't be determined"
- [ ! -d "${descdir}" ] && error "${descdir} does not exist or is not a directory"
- [ ! -r "${descdir}/use.desc" ] && error "${descdir}/use.desc is not readable"
- [ ! -r "${descdir}/use.local.desc" ] && error "${descdir}/use.local.desc is not readable"
- [ ! -r "$(get_make_defaults)" ] && error "$(get_make_defaults) is not readable"
- [ "${MODE}" == "modify" -a ! -w "${MAKE_CONF_PATH}" ] && error ""${MAKE_CONF_PATH}" is not writable"
- }
-
- showhelp() {
- echo "${PROGRAM_NAME} v${PROGRAM_VERSION}"
- echo
- echo "Syntax: ${PROGRAM_NAME} <option> [suboptions] [useflaglist]"
- echo
- echo "Options: -h, --help - show this message"
- echo " -v, --version - show version information"
- echo " -i, --info - show descriptions for the given useflags"
- echo " -g, --global - show only global use flags (suboption)"
- echo " -l, --local - show only local use flags (suboption)"
- echo " -a, --active - show currently active useflags and their origin"
- echo " -E, --enable - enable the given useflags"
- echo " -D, --disable - disable the given useflags"
- echo " -P, --prune - remove all references to the given flags from"
- echo " make.conf to revert to default settings"
- echo
- echo "Notes: ${PROGRAM_NAME} currently only works for global flags defined"
- echo " in make.globals, make.defaults or make.conf, it doesn't handle"
- echo " use.defaults, use.mask or package.use yet (see portage(5) for details on"
- echo " these files). It also might have issues with cascaded profiles."
- echo " If multiple options are specified only the last one will be used."
- }
-
- showversion() {
- echo "${PROGRAM_NAME} v${PROGRAM_VERSION}"
- echo "Written by Marius Mauch"
- echo
- echo "Copyright (C) 2004 Gentoo Foundation, Inc."
- echo "This is free software; see the source for copying conditions."
- }
-
- # the following function creates a bash array ACTIVE_FLAGS that contains the
- # global use flags, indexed by origin: 0: environment, 1: make.conf,
- # 2: make.defaults, 3: make.globals
- get_useflags() {
- # only calculate once as calling emerge is painfully slow
- [ -n "${USE_FLAGS_CALCULATED}" ] && return
-
- # backup portdir so get_portdir() doesn't give false results later
- portdir_backup="${PORTDIR}"
-
- ACTIVE_FLAGS[0]="${USE}"
- USE=""
- source "${MAKE_CONF_PATH}"
- ACTIVE_FLAGS[1]="${USE}"
- USE=""
- for x in $(get_all_make_defaults); do
- source "${x}"
- ACTIVE_FLAGS[2]="${ACTIVE_FLAGS[2]} ${USE}"
- done
- USE=""
- source "${MAKE_GLOBALS_PATH}"
- ACTIVE_FLAGS[3]="${USE}"
-
- # restore saved env variables
- USE="${ACTIVE_FLAGS[0]}"
- PORTDIR="${portdir_backup}"
-
- # get the currently active USE flags as seen by portage, this has to be after
- # restoring USE or portage won't see the original environment
- ACTIVE_FLAGS[9]="$(emerge --info | grep 'USE=' | cut -b 5- | sed -e 's:"::g')" #'
- USE_FLAGS_CALCULATED=1
- }
-
- # get the list of all known USE flags by reading use.desc and/or use.local.desc
- # (depending on the value of $SCOPE)
- get_useflaglist() {
- local descdir
-
- descdir="$(get_portdir)/profiles"
-
- if [ -z "${SCOPE}" -o "${SCOPE}" == "global" ]; then
- egrep "^[^# ]+ +-" "${descdir}/use.desc" | cut -d\ -f 1
- fi
- if [ -z "${SCOPE}" -o "${SCOPE}" == "local" ]; then
- egrep "^[^# :]+:[^ ]+ +-" "${descdir}/use.local.desc" | cut -d: -f 2 | cut -d\ -f 1
- fi
- }
-
- # get all make.defaults by traversing the cascaded profile directories
- get_all_make_defaults() {
- local curdir
- local parent
- local rvalue
-
- curdir="$(readlink -f ${MAKE_PROFILE_PATH})"
-
- while [ -f "${curdir}/parent" ]; do
- [ -f "${curdir}/make.defaults" ] && rvalue="${curdir}/make.defaults ${rvalue}"
- parent="$(egrep -v '(^#|^ *$)' ${curdir}/parent)"
- curdir="$(readlink -f ${curdir}/${parent})"
- done
-
- echo "${rvalue}"
- }
-
- # get the path to make.defaults by traversing the cascaded profile directories
- get_make_defaults() {
- local curdir
- local parent
-
- curdir="$(readlink -f ${MAKE_PROFILE_PATH})"
-
- while [ ! -f "${curdir}/make.defaults" -a -f "${curdir}/parent" ]; do
- parent="$(egrep -v '(^#|^ *$)' ${curdir}/parent)"
- curdir="$(readlink -f ${curdir}/${parent})"
- done
-
- echo "${curdir}/make.defaults"
- }
-
- # little helper function to get the status of a given flag in one of the
- # ACTIVE_FLAGS elements. Arguments are 1: flag to test, 2: index of ACTIVE_FLAGS,
- # 3: echo value for positive (and as lowercase for negative) test result,
- # 4 (optional): echo value for "missing" test result, defaults to blank
- get_flagstatus_helper() {
- if echo " ${ACTIVE_FLAGS[${2}]} " | grep " ${1} " > /dev/null; then
- echo -n "${3}"
- elif echo " ${ACTIVE_FLAGS[${2}]} " | grep " -${1} " > /dev/null; then
- echo -n "$(echo ${3} | tr [[:upper:]] [[:lower:]])"
- else
- echo -n "${4:- }"
- fi
- }
-
- # prints a status string for the given flag, each column indicating the presence
- # for portage, in the environment, in make.conf, in make.defaults and in make.globals.
- # full positive value would be "[+ECDG]", full negative value would be [-ecdg],
- # full missing value would be "[- ]" (portage only sees present or not present)
- get_flagstatus() {
- get_useflags
-
- echo -n '['
- get_flagstatus_helper "${1}" 9 "+" "-"
- get_flagstatus_helper "${1}" 0 "E"
- get_flagstatus_helper "${1}" 1 "C"
- get_flagstatus_helper "${1}" 2 "D"
- get_flagstatus_helper "${1}" 3 "G"
- echo -n '] '
- }
-
- # faster replacement to `portageq portdir`
- get_portdir() {
- if [ -z "${PORTDIR}" ]; then
- use_backup="${USE}"
- source "${MAKE_GLOBALS_PATH}"
- for x in $(get_all_make_defaults); do
- source "${x}"
- done
- source "${MAKE_CONF_PATH}"
- USE="${use_backup}"
- fi
- echo "${PORTDIR}"
- }
-
- # This function takes a list of use flags and shows the status and
- # the description for each one, honoring $SCOPE
- showdesc() {
- local descdir
- local current_desc
- local found_one
- local args
-
- args="${*:-*}"
-
- if [ -z "${SCOPE}" ]; then
- SCOPE="global" showdesc ${args}
- echo
- SCOPE="local" showdesc ${args}
- return
- fi
-
- descdir="$(get_portdir)/profiles"
-
- [ "${SCOPE}" == "global" ] && echo "global use flags (searching: ${args})"
- [ "${SCOPE}" == "local" ] && echo "local use flags (searching: ${args})"
- echo "************************************************************"
-
- if [ "${args}" == "*" ]; then
- args="$(get_useflaglist | sort -u)"
- fi
-
- set ${args}
-
- foundone=0
- while [ -n "${1}" ]; do
- if [ "${SCOPE}" == "global" ]; then
- if grep "^${1} *-" "${descdir}/use.desc" > /dev/null; then
- get_flagstatus "${1}"
- foundone=1
- fi
- grep "^${1} *-" "${descdir}/use.desc"
- fi
- # local flags are a bit more complicated as there can be multiple
- # entries per flag and we can't pipe into printf
- if [ "${SCOPE}" == "local" ]; then
- if grep ":${1} *-" "${descdir}/use.local.desc" > /dev/null; then
- foundone=1
- fi
- grep ":${1} *-" "${descdir}/use.local.desc" \
- | sed -e "s/^\([^:]\+\):\(${1}\) *- *\(.\+\)/\1|\2|\3/g" \
- | while read line; do
- pkg="$(echo $line | cut -d\| -f 1)"
- flag="$(echo $line | cut -d\| -f 2)"
- desc="$(echo $line | cut -d\| -f 3)"
- get_flagstatus "${flag}"
- printf "%s (%s):\n%s\n\n" "${flag}" "${pkg}" "${desc}"
- done
- fi
- shift
- done
-
- if [ ${foundone} == 0 ]; then
- echo "no matching entries found"
- fi
- }
-
- # show a list of all currently active flags and where they are activated
- showflags() {
- local args
-
- get_useflags
-
- args="${*:-*}"
-
- if [ "${args}" == "*" ]; then
- args="$(get_useflaglist | sort -u)"
- fi
-
- set ${args}
-
- while [ -n "${1}" ]; do
- if echo " ${ACTIVE_FLAGS[9]} " | grep " ${1} " > /dev/null; then
- printf "%-20s" ${1}
- get_flagstatus ${1}
- echo
- fi
- shift
- done
- }
-
- # two small helpers to add or remove a flag from a USE string
- add_flag() {
- NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE} ${1}"
- }
-
- remove_flag() {
- NEW_MAKE_CONF_USE="${NEW_MAKE_CONF_USE// ${1} / }"
- }
-
- # USE flag modification function. Mainly a loop with calls to add_flag and
- # remove_flag to create a new USE string which is then inserted into make.conf.
- modify() {
- if [ -z "${*}" ]; then
- if [ "${ACTION}" != "prune" ]; then
- echo "WARNING: no USE flags listed for modification, do you really"
- echo " want to ${ACTION} *all* known USE flags?"
- echo " If you don't please press Ctrl-C NOW!!!"
- sleep 5
- set $(get_useflaglist | sort -u)
- fi
- fi
-
- get_useflags
-
- NEW_MAKE_CONF_USE=" ${ACTIVE_FLAGS[1]} "
-
- while [ -n "${1}" ]; do
- if [ "${ACTION}" == "add" ]; then
- if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
- shift
- elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
- remove_flag "-${1}"
- else
- add_flag "${1}"
- shift
- fi
- elif [ "${ACTION}" == "remove" ]; then
- if echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
- shift
- elif echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
- remove_flag "${1}"
- else
- add_flag "-${1}"
- shift
- fi
- elif [ "${ACTION}" == "prune" ]; then
- if echo " ${NEW_MAKE_CONF_USE} " | grep " ${1} " > /dev/null; then
- remove_flag "${1}"
- elif echo " ${NEW_MAKE_CONF_USE} " | grep " -${1} " > /dev/null; then
- remove_flag "-${1}"
- fi
- shift
- fi
- done
-
- #echo "old flags:"
- #echo ${ACTIVE_FLAGS[1]}
- #echo
- #echo "new flags:"
- #echo ${NEW_MAKE_CONF_USE}
-
- # a little loop to add linebreaks so we don't end with one ultra-long line
- NEW_MAKE_CONF_USE_2=""
- for x in ${NEW_MAKE_CONF_USE}; do
- if [ $(((${#NEW_MAKE_CONF_USE_2}%70)+${#x}+2)) -gt 70 ]; then
- NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}\\ \\n $x "
- else
- NEW_MAKE_CONF_USE_2="${NEW_MAKE_CONF_USE_2}${x} "
- fi
- done
-
- # make a backup just in case the user doesn't like the new make.conf
- cp -p "${MAKE_CONF_PATH}" "${MAKE_CONF_BACKUP_PATH}"
-
- # as sed doesn't really work with multi-line patterns we have to replace USE
- # on our own here. Basically just skip everything between USE=" and the
- # closing ", printing our new USE line there instead.
- inuse=0
- (while read -r line; do
- [ "${line:0:4}" == "USE=" ] && inuse=1
- [ "${inuse}" == "0" ] && echo -E "${line}"
- if [ "${inuse}" == "1" ] && echo "${line}" | egrep '" *(#.*)?$' > /dev/null; then
- echo -n 'USE="'
- echo -ne "${NEW_MAKE_CONF_USE_2%% }"
- echo '"'
- inuse=0
- fi
- done ) < "${MAKE_CONF_BACKUP_PATH}" | sed -e 's:\\ $:\\:' > "${MAKE_CONF_PATH}"
-
- echo "${MAKE_CONF_PATH} was modified, a backup copy has been placed at ${MAKE_CONF_BACKUP_PATH}"
- }
-
- ##### main program comes now #####
-
- # disable globbing as it fucks up with args=*
- set -f
- parse_arguments "$@"
- check_sanity
-
- eval ${MODE} ${ARGUMENTS}
- set +f
-